﻿// Dynamic tree editor - tree-like data structures editor for .NET/Mono.
// Copyright (C) 2006  Vladimir Sibirov
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Text.RegularExpressions;

// TODO: Russian localization

namespace TreeEditor
{
	/// <summary>
	/// Document form for main MDI window.
	/// </summary>
	public partial class DocForm
	{
		// Document-specific variables
		private Tree tree;
		private uint buffId;
		private TreeNode buffTreeNode;
		private string defaultClass;
		private string culture;
		private bool defaultClicked;
		private bool modifiedDisplay;
		
		/// <summary>
		/// Form constructor.
		/// </summary>
		public DocForm()
		{			
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();
			
			//
			// TODO: Add constructor code after the InitializeComponent() call.
			//
			defaultClass = null;
			defaultClicked = false;
		}
		
		/// <summary>
		/// I18n culture info.
		/// </summary>
		internal string Culture
		{
			get
			{
				return culture;
			}
			set
			{
				culture = value;
			}
		}
		
		/// <summary>
		/// Creates blank document.
		/// </summary>
		internal void NewDoc()
		{
			string treeName = (culture == "ru") ? "Имя дерева" : "Tree name";
			tree = new Tree(treeName, (culture == "ru"));
			tree.Culture = culture;
			tree.ModifiedStateChanged += new Tree.ModifiedStateHandler(TreeModifiedStateChanged);
			relChildGrid.DataSource = null;
			relChildGrid.CaptionText = tree.Name;
			relSelGrid.DataSource = null;
			relSelGrid.CaptionText = tree.Name;
			treeView.Nodes.Clear();
			treeView.Name = tree.Name;
			treeNameBox.Text = tree.Name;
			this.Text = tree.Name;
			RefreshView();
		}
		
		/// <summary>
		/// Handles document opening.
		/// </summary>
		/// <param name="fileName">Document path.</param>
		internal void OpenDoc(string fileName)
		{
			tree = new Tree("Tree Name", fileName);
			tree.Culture = culture;
			tree.ModifiedStateChanged += new Tree.ModifiedStateHandler(TreeModifiedStateChanged);
			relChildGrid.DataSource = null;
			relChildGrid.CaptionText = tree.Name;
			relSelGrid.DataSource = null;
			relSelGrid.CaptionText = tree.Name;
			treeView.Nodes.Clear();
			treeView.Name = tree.Name;
			treeNameBox.Text = tree.Name;
			this.Text = tree.Name;
			RefreshView();
			RefreshClassList();
			RefreshClassDropDown(this.searchClassCombo);
			RefreshClassDropDown(this.selNodeClass);
			RefreshClassDropDown(this.childClass);
		}
		
		/// <summary>
		/// Shows the Save File dialog.
		/// </summary>
		internal void SaveAs()
		{
			SaveFileDialog sfd = new SaveFileDialog();
			sfd.FileName = tree.Name;
			//sfd.CheckPathExists = true;
			sfd.Filter = (culture == "ru") ? "XML документы деревьев (*.tree)|*.tree" : "Tree XML documents (*.tree)|*.tree";
			sfd.ShowDialog();
			tree.SaveAs(sfd.FileName);
		}
		
		/// <summary>
		/// Saves the document.
		/// </summary>
		internal void Save()
		{
			if(tree.FileName != null)
			{
				tree.Save();
			}
			else
			{
				SaveAs();
			}
		}

		/// <summary>
		/// Handles document closing.
		/// </summary>
		/// <returns>True on close, false on cancel.</returns>
		internal bool CloseDoc()
		{
			// Check whether document is saved
			if(tree.FileName == null || tree.FileName == "" || tree.Modified)
			{
				SaveChangesDialog askSave = new SaveChangesDialog();
				askSave.DocName = tree.FileName;
				askSave.ShowDialog();
				if(askSave.DialogResult == DialogResult.Yes)
				{
					if(tree.FileName == null || tree.FileName == "")
						SaveAs();
					else
						tree.Save();
				}
				else if(askSave.DialogResult == DialogResult.Cancel)
				{
					return false;
				}
			}
			// Clean resources
			this.Close();
			return true;
		}
		
		/// <summary>
		/// Clears the document.
		/// </summary>
		internal void ClearDoc()
		{
			// Clear the grids
			dataSelGrid.DataSource = null;
			dataSelGrid.CaptionText = tree.Name;
			dataChildGrid.DataSource = null;
			dataChildGrid.CaptionText = tree.Name;
			relSelGrid.DataSource = null;
			relSelGrid.CaptionText = tree.Name;
			relChildGrid.DataSource = null;
			relChildGrid.CaptionText = tree.Name;
			// Clear the tree view
			tree.Clear();
			// Clear the parts
			RefreshView();
			RefreshClassList();
			RefreshClassEditor();
			RefreshColumnEditor();
			
		}
		
		/// <summary>
		/// Handles the tree renaming action
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		private void RenameTree(object sender, System.EventArgs e)
		{
			tree.Name = treeNameBox.Text;
			relChildGrid.CaptionText = treeNameBox.Text;
			relSelGrid.CaptionText = treeNameBox.Text;
			treeView.Name = treeNameBox.Text;
			this.Text = tree.Name;
		}
		
		/// <summary>
		/// Regenerates the treeView due to the tree structure.
		/// </summary>
		private void RefreshView()
		{
			treeView.BeginUpdate();
			treeView.Nodes.Clear();
			RefreshView(tree.Root, treeView.Nodes);
			treeView.EndUpdate();
		}

		/// <summary>
		/// Recursively walks the tree and generates its view
		/// </summary>
		/// <param name="node">Current node.</param>
		/// <param name="treeNodes">Control child nodes collection.</param>
		private void RefreshView(Node node, TreeNodeCollection treeNodes)
		{
			// Adding current node to the treeView
			TreeNode currentNode = new TreeNode(node.Name);
			currentNode.Tag = node.Id;
			treeNodes.Add(currentNode);
			// Adding all the node children to the treeView
			Node[] children = node.Children;
			for(uint i = 0; i < children.Length; i++)
			{
				if(children[i].Id != 0) RefreshView(children[i], currentNode.Nodes);
			}
		}
		
		/// <summary>
		/// Refreshes the class list due to the tree classes
		/// </summary>
		private void RefreshClassList()
		{
			this.classList.Items.Clear();
			for(int i = 0; i < tree.Classes.Count; i++)
			{
				// Adding the class name to the list
				this.classList.Items.Add(((Class) tree.Classes.GetByIndex(i)).Name);
			}
			if(tree.Classes.Count == 0)
				this.groupClassEdit.Enabled = false;
		}
		
		/// <summary>
		/// Refreshes the column list due to the class columns
		/// </summary>
		private void RefreshClassEditor()
		{
			this.colList.Items.Clear();
			if(this.classList.SelectedIndex >= 0)
			{
				Class cls = (Class) tree.Classes.GetByIndex(this.classList.SelectedIndex);
				this.classNameBox.Text = cls.Name;
				for(int i = 0; i < cls.Columns.Count; i++)
				{
					this.colList.Items.Add(((Column) cls.Columns.GetByIndex(i)).Name);
				}
			}
			else
			{
				this.classNameBox.Text = "";
			}
			if(colList.Items.Count == 0)
				this.groupColEdit.Enabled = false;
		}
		
		/// <summary>
		/// Refreshes the column editor due to the column selected
		/// </summary>
		private void RefreshColumnEditor()
		{
			if(this.colList.SelectedIndex < 0)
			{
				// Cleaning the fields
				this.groupColEdit.Enabled = false;
			}
			else
			{
				// Loading the column
				Column col = (Column) ((Class) tree.Classes.GetByIndex(this.classList.SelectedIndex)).Columns.GetByIndex(this.colList.SelectedIndex);
				this.colNameBox.Text = col.Name;
				if(col.DataType == typeof(string))
					this.colTypeCombo.SelectedIndex = 0;
				if(col.DataType == typeof(byte))
					this.colTypeCombo.SelectedIndex = 1;
				if(col.DataType == typeof(int))
					this.colTypeCombo.SelectedIndex = 2;
				if(col.DataType == typeof(long))
					this.colTypeCombo.SelectedIndex = 3;
				if(col.DataType == typeof(double))
					this.colTypeCombo.SelectedIndex = 4;
				if(col.DataType == typeof(bool))
					this.colTypeCombo.SelectedIndex = 5;
				this.colCaptionBox.Text = col.Caption;
				if(col.MaxLength >= 0)
					this.colLengthBox.Text = col.MaxLength.ToString();
				else
					this.colLengthBox.Text = null;
				this.colFilterBox.Text = col.Filter;
				this.colDefaultBox.Text = col.DefaultValue.ToString();
				this.colAllowNullBox.Checked = col.AllowNull;
				this.colReadOnlyBox.Checked = col.ReadOnly;
				this.colUniqueBox.Checked = col.Unique;
				this.colAutoBox.Checked = col.AutoIncrement;
				if(col.AutoIncrement)
				{
					this.colAutoStartBox.Text = col.AutoIncrementStart.ToString();
					this.colAutoStepBox.Text = col.AutoIncrementStep.ToString();
				}
			}
		}
		
		/// <summary>
		/// Refreshes the node data grid.
		/// </summary>
		/// <param name="node">Current node.</param>
		private void RefreshNodeView(Node node)
		{
			// Refresh the relation grids
			relSelGrid.DataSource = node.ViewInfo();
			relSelGrid.CaptionText = node.Name;
			// Load the data into editor
			dataSelGrid.DataSource = node.View();
			if(node.ClassId > 0)
				dataSelGrid.CaptionText = node.Name;
			else
				dataSelGrid.CaptionText = (culture == "ru") ? "Данные отстутствуют в этом классе" : "No data for this class";
		}
		
		/// <summary>
		/// Refreshes the child data grid.
		/// </summary>
		/// <param name="node">Current node.</param>
		private void RefreshChildrenView(Node node)
		{
			// Auxilliary grid
			relChildGrid.DataSource = node.ViewChildrenInfo();
			relChildGrid.CaptionText = node.Name;
			// Data editor grid
			Class flt;
			if(this.childClass.SelectedIndex == -1)
				flt = null;
			else
				flt = (Class) tree.Classes[this.childClass.Items[this.childClass.SelectedIndex]];
			// Assemble the child view
			dataChildGrid.DataSource = node.ViewChildren(flt);
			if(flt == null)
				dataChildGrid.CaptionText = (culture == "ru") ? "Отсутствует класс или узлы-потомки" : "Empty class or no children found";
			else
				dataChildGrid.CaptionText = flt.Name;
		}
		
		/// <summary>
		/// Refreshes combo due to the current class list
		/// </summary>
		/// <param name="combo"></param>
		private void RefreshClassDropDown(ComboBox combo)
		{
			combo.Items.Clear();
			for(int i = 0; i < tree.Classes.Count; i++)
			{
				Class cls = (Class) tree.Classes.GetByIndex(i);
				combo.Items.Add(cls.Name);
			}
			if(defaultClass != null)
				combo.SelectedIndex = combo.Items.IndexOf(defaultClass);
		}
		
		/// <summary>
		/// Validates the tree name input.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		private void TreeNameBoxValidating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			Regex re = new Regex(@"^[\w_\ \-]+$");
			if(re.IsMatch(treeNameBox.Text))
			{
				e.Cancel = false;				
			}
			else
			{
				if(culture == "ru")
					MessageBox.Show("Имя может содержать буквы, цифры, пробел, знаки подчеркивания и дефис.", "Неверный ввод");
				else
					MessageBox.Show("The name can contain alphanumeric characters, spaces, underscores and dashes.", "Wrong input");
				e.Cancel = true;
			}
		}
		
		/// <summary>
		/// Auxilliary actions on form load.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		private void DocFormLoad(object sender, System.EventArgs e)
		{
			// Add aux stuff here.
		}
		
		/// <summary>
		/// Select event handler.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void TreeViewAfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
		{
			// Getting the node
			Node node = new Node(tree, uint.Parse(e.Node.Tag.ToString()));
			// Just refresh the views
			RefreshNodeView(node);
			RefreshChildrenView(node);
		}
		
		/// <summary>
		/// Checks and changes selected node's name.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void TreeViewAfterLabelEdit(object sender, System.Windows.Forms.NodeLabelEditEventArgs e)
		{
			// Simply getting the node and updating its name
			// Validation is disabled (commented out)
			// Regex re = new Regex(@"^[\w_\ \-]+$");
			if(e.Label != null/* && re.IsMatch(e.Label)*/)
			{
				// Changed properly
				Node node = new Node(tree, uint.Parse(e.Node.Tag.ToString()));
				node.Name = e.Label;
				node.Update();
				e.CancelEdit = false;
				treeView.LabelEdit = false;
			}
			else if(e.Label == null)
			{
				// Unchanged
				e.CancelEdit = true;
				treeView.LabelEdit = false;
			}
			/*else
			{
				// Changed unproperly
				if(culture == "ru")
					MessageBox.Show("Имя может содержать буквы, цифры, пробел, знаки подчеркивания и дефис.", "Неверный ввод");
				else
					MessageBox.Show("The name can contain alphanumeric characters, spaces, underscores and dashes.", "Wrong input");
				// Try again
				e.CancelEdit = true;
				e.Node.BeginEdit();
			}*/
		}
		
		/// <summary>
		/// Sets the active node.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void TreeViewMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			Point pointClick = treeView.PointToClient(Cursor.Position);
			TreeNode clickedNode = treeView.GetNodeAt(pointClick);
			treeView.SelectedNode = clickedNode;
		}
		
		/// <summary>
		/// Enables/disables menu elements due to the situation context.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void TreeMenuOpening(object sender, System.ComponentModel.CancelEventArgs e)
		{
			if(treeView.SelectedNode == null)
			{
				renameToolStripMenuItem.Enabled = false;
				insertToolStripMenuItem.Enabled = false;
				deleteToolStripMenuItem.Enabled = false;
				cutToolStripMenuItem.Enabled = false;
				pasteToolStripMenuItem.Enabled = false;
				addChildToolStripMenuItem.Enabled = false;
				removeChildrenToolStripMenuItem.Enabled = false;
			}
			else
			{
				renameToolStripMenuItem.Enabled = true;
				if(treeView.SelectedNode != treeView.TopNode)
				{
					insertToolStripMenuItem.Enabled = true;
					deleteToolStripMenuItem.Enabled = true;
					cutToolStripMenuItem.Enabled = true;
				}
				else
				{
					insertToolStripMenuItem.Enabled = false;
					deleteToolStripMenuItem.Enabled = false;
					cutToolStripMenuItem.Enabled = false;
				}
				if(buffTreeNode != null)
					pasteToolStripMenuItem.Enabled = true;
				else
					pasteToolStripMenuItem.Enabled = false;
				addChildToolStripMenuItem.Enabled = true;
				removeChildrenToolStripMenuItem.Enabled = true;
			}
		}
		
		/// <summary>
		/// Enters renaming mode.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void RenameToolStripMenuItemClick(object sender, System.EventArgs e)
		{
			treeView.LabelEdit = true;
			treeView.SelectedNode.BeginEdit();
		}
		
		/// <summary>
		/// Copies the branch to the "clipboard".
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void CutToolStripMenuItemClick(object sender, System.EventArgs e)
		{
			buffId = uint.Parse(treeView.SelectedNode.Tag.ToString());
			if(buffTreeNode != null && buffTreeNode.ForeColor == Color.Gray)
				buffTreeNode.ForeColor = Color.Black;
			buffTreeNode = treeView.SelectedNode;
			buffTreeNode.ForeColor = Color.Gray;
		}
		
		/// <summary>
		/// Moves the branch from the "clipboard" to the new parent.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void PasteToolStripMenuItemClick(object sender, System.EventArgs e)
		{
			Node node = new Node(tree, buffId);
			TreeNode target = treeView.SelectedNode;
			if(node.Move(uint.Parse(target.Tag.ToString())))
			{
				buffTreeNode.Parent.Nodes.Remove(buffTreeNode);
				target.Nodes.Add(buffTreeNode);
				target.Expand();
				treeView.SelectedNode = buffTreeNode;
				buffTreeNode.ForeColor = Color.Black;
			}
		}
		
		/// <summary>
		/// Inserts a new node into this branch.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void InsertToolStripMenuItemClick(object sender, System.EventArgs e)
		{
			// No root-level insert!
			Node node = new Node(tree, uint.Parse(treeView.SelectedNode.Tag.ToString()));
			if(node.Depth == 0)
				return;
			// OK, adding a brother node (another child of the parent)
			string nodeName = (culture == "ru") ? "Новый узел" : "New node";
			Node parent = new Node(tree, uint.Parse(treeView.SelectedNode.Parent.Tag.ToString()));
			node = new Node(tree, nodeName, parent.Id);
			TreeNode treeNode = new TreeNode(nodeName);
			node.Add();
			treeNode.Tag = node.Id;
			treeView.SelectedNode.Parent.Nodes.Add(treeNode);
			treeView.SelectedNode = treeNode;
			treeView.LabelEdit = true;
			treeView.SelectedNode.BeginEdit();
		}
		
		/// <summary>
		/// Deletes selected node.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void DeleteToolStripMenuItemClick(object sender, System.EventArgs e)
		{
			// No root-level delete!
			Node node = new Node(tree, uint.Parse(treeView.SelectedNode.Tag.ToString()));
			if(node.Depth == 0)
				return;
			// OK, removing the selected node
			if(node.Delete() > 0)
				treeView.SelectedNode.Remove();
		}
		
		/// <summary>
		/// Inserts a child node.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void AddChildToolStripMenuItemClick(object sender, System.EventArgs e)
		{
			// Creating a child node and adding it to the dataset/treeview
			string nodeName = (culture == "ru") ? "Новый узел" : "New node";
			Node node = new Node(tree, nodeName, uint.Parse(treeView.SelectedNode.Tag.ToString()));
			TreeNode treeNode = new TreeNode(nodeName);
			node.Add();
			treeNode.Tag = node.Id;
			treeView.SelectedNode.Nodes.Add(treeNode);
			treeView.SelectedNode = treeNode;
			treeView.LabelEdit = true;
			treeView.SelectedNode.BeginEdit();
		}
		
		/// <summary>
		/// Removes all the node children.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void RemoveChildrenToolStripMenuItemClick(object sender, System.EventArgs e)
		{
			Node node = new Node(tree, uint.Parse(treeView.SelectedNode.Tag.ToString()));
			Node[] children = node.Children;
			for(int i = 0; i < children.Length; i++)
			{
				children[i].Delete();
			}
			treeView.SelectedNode.Nodes.Clear();
		}
		
		/// <summary>
		/// Class selection.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ClassListSelectedIndexChanged(object sender, System.EventArgs e)
		{
			defaultClicked = false;
			// Drop the column index
			this.colList.SelectedIndex = -1;
			// Refresh
			RefreshClassEditor();
			if(this.classList.SelectedIndex >= 0)
			{
				// Class list controls
				this.classDel.Enabled = true;
				this.classCopy.Enabled = true;
				this.classSetDefault.Enabled = true;
				if(defaultClass != null && this.classList.SelectedIndex == classList.Items.IndexOf(defaultClass))
					this.classSetDefault.Checked = true;
				else
					this.classSetDefault.Checked = false;
				// Class editor controls
				this.groupClassEdit.Enabled = true;
			}
			else
			{
				// Class list controls
				this.classDel.Enabled = false;
				this.classCopy.Enabled = false;
				this.classSetDefault.Enabled = false;
				// Class editor controls
				this.groupClassEdit.Enabled = false;
			}
		}
		
		/// <summary>
		/// Adds a new class.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ClassAddClick(object sender, System.EventArgs e)
		{
			// Class names must be unique!
			string className = (culture == "ru") ? "Новый класс" : "New class";
			// Appending a tail if needed
			bool exists;
			uint num = 0;
			string temp;
			do
			{
				exists = false;
				if(num == 0)
					temp = className;
				else
					temp = className + num.ToString();
				for(int i = 0; i < tree.Classes.Count; i++)
				{
					if(((Class) tree.Classes.GetByIndex(i)).Name == temp)
					{
						exists = true;
						break;
					}
				}
				num++;
			}
			while(exists);
			className = temp;
			// Adding the class
			Class cls = new Class(className, tree);
			cls.Add();
			tree.Classes.Add(className, (object) cls);
			int index = this.classList.Items.Add(cls.Name);
			this.classList.SelectedIndex = index;
			RefreshClassEditor();
			RefreshClassDropDown(this.searchClassCombo);
			RefreshClassDropDown(this.selNodeClass);
			RefreshClassDropDown(this.childClass);
		}
		
		/// <summary>
		/// Removes the class.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ClassDelClick(object sender, System.EventArgs e)
		{
			RemoveClassDialog rcd = new RemoveClassDialog();
			rcd.ShowDialog();
			if(rcd.DialogResult == DialogResult.OK)
			{
				// Removing the class
				Class cls = (Class) tree.Classes.GetByIndex(this.classList.SelectedIndex);
				if(defaultClass != null && classList.Items.IndexOf(defaultClass) == this.classList.SelectedIndex)
				{
					defaultClass = null;
				}
				cls.Remove(rcd.WithNodes);
				this.classList.Items.RemoveAt(this.classList.SelectedIndex);
				RefreshClassDropDown(this.searchClassCombo);
				RefreshClassDropDown(this.selNodeClass);
				RefreshClassDropDown(this.childClass);
			}
		}
		
		/// <summary>
		/// Creates a new class based on selected one.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void ClassCopyClick(object sender, System.EventArgs e)
		{
			// Class names must be unique!
			string className = (culture == "ru") ? "Новый класс" : "New class";
			// Appending a tail if needed
			bool exists;
			uint num = 0;
			string temp;
			do
			{
				exists = false;
				if(num == 0)
					temp = className;
				else
					temp = className + num.ToString();
				for(int i = 0; i < tree.Classes.Count; i++)
				{
					if(((Class) tree.Classes.GetByIndex(i)).Name == temp)
					{
						exists = true;
						break;
					}
				}
				num++;
			}
			while(exists);
			className = temp;
			// Creating the class
			Class cls = new Class(className, tree);
			cls.Add();
			// Inheriting a selected one
			cls.Inherit((Class) tree.Classes.GetByIndex(this.classList.SelectedIndex));
			// Adding
			tree.Classes.Add(className, (Object) cls);
			int index = this.classList.Items.Add(cls.Name);
			this.classList.SelectedIndex = index;
			RefreshClassEditor();
			RefreshClassDropDown(this.searchClassCombo);
			RefreshClassDropDown(this.selNodeClass);
			RefreshClassDropDown(this.childClass);
		}
		
		/// <summary>
		/// Validates class name.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ClassNameBoxValidating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			// Don't validate if nothing is selected
			if(this.classList.SelectedIndex < 0)
			{
				e.Cancel = false;
				return;
			}
			// Checking the syntax
			Regex re = new Regex(@"^[\w_\ \-]+$");
			if(re.IsMatch(this.classNameBox.Text))
			{
				bool exists = false;
				for(int i = 0; i < tree.Classes.Count; i++)
				{
					if(i != this.classList.SelectedIndex && ((Class) tree.Classes.GetByIndex(i)).Name == this.classNameBox.Text)
					{
						exists = true;
						break;
					}
				}
				if(exists)
				{
					if(culture == "ru")
						MessageBox.Show("Имя класса должно быть уникальным.", "Неверный ввод");
					else
						MessageBox.Show("Class name must be unique.", "Wrong input");
					e.Cancel = true;
				}
				else
					e.Cancel = false;
			}
			else
			{
				if(culture == "ru")
					MessageBox.Show("Имя может содержать буквы, цифры, пробел, знаки подчеркивания и дефис.", "Неверный ввод");
				else
					MessageBox.Show("The name can contain alphanumeric characters, spaces, underscores and dashes.", "Wrong input");
				e.Cancel = true;
			}
		}
		
		/// <summary>
		/// Renames the class.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void BtnClassRenameClick(object sender, System.EventArgs e)
		{
			// We guess the name is already validated
			Class cls = (Class) tree.Classes.GetByIndex(this.classList.SelectedIndex);
			// Save the old name for further checks
			string oldName = cls.Name;
			cls.Name = this.classNameBox.Text;
			cls.Update();
			//this.classList.Items[this.classList.SelectedIndex] = cls.Name;
			RefreshClassList();
			// Change default name if this one is default
			if(defaultClass == oldName)
				defaultClass = cls.Name;
			// Find the new index
			this.classList.SelectedIndex = this.classList.Items.IndexOf(cls.Name);
			// Refresh combos
			RefreshClassDropDown(this.searchClassCombo);
			RefreshClassDropDown(this.selNodeClass);
			RefreshClassDropDown(this.childClass);
		}
		
		/// <summary>
		/// Column selection
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColListSelectedIndexChanged(object sender, System.EventArgs e)
		{
			if(this.colList.SelectedIndex >= 0)
			{
				// Column list controls
				this.colDelBtn.Enabled = true;
				this.colCopyBtn.Enabled = true;
				// Class editor controls
				this.groupColEdit.Enabled = true;
				RefreshColumnEditor();
			}
			else
			{
				// Class list controls
				this.colDelBtn.Enabled = false;
				this.colCopyBtn.Enabled = false;
				// Class editor controls
				this.groupColEdit.Enabled = false;
			}
		}
		
		/// <summary>
		/// Adds a new column.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColAddBtnClick(object sender, System.EventArgs e)
		{
			// Getting the class
			Class cls = (Class) tree.Classes.GetByIndex(this.classList.SelectedIndex);
			// Column names must be unique!
			string colName = (culture == "ru") ? "Поле" : "Column";
			// Appending a tail if needed
			bool exists;
			uint num = 0;
			string temp;
			do
			{
				exists = false;
				if(num == 0)
					temp = colName;
				else
					temp = colName + num.ToString();
				for(int i = 0; i < cls.Columns.Count; i++)
				{
					if(((Column) cls.Columns.GetByIndex(i)).Name == temp)
					{
						exists = true;
						break;
					}
				}
				num++;
			}
			while(exists);
			colName = temp;
			// Showing a dialog
			NewColumnDialog ncd = new NewColumnDialog();
			ncd.Culture = culture;
			ncd.ParentClass = cls;
			ncd.colNameBox.Text = colName;
			ncd.ShowDialog();
			// Setting the column up
			colName = ncd.colNameBox.Text;
			Column col = new Column(colName, cls);
			switch(ncd.colTypeCombo.SelectedIndex)
			{
				case 0:
					col.DataType = typeof(string);
					break;
				case 1:
					col.DataType = typeof(byte);
					break;
				case 2:
					col.DataType = typeof(int);
					break;
				case 3:
					col.DataType = typeof(long);
					break;
				case 4:
					col.DataType = typeof(double);
					break;
				case 5:
					col.DataType = typeof(bool);
					break;
			}
			if(ncd.colCaptionBox.Text != null)
				col.Caption = ncd.colCaptionBox.Text;
			if(ncd.colLengthBox.Text != null && ncd.colLengthBox.Text != "")
				col.MaxLength = int.Parse(ncd.colLengthBox.Text);
			if(ncd.colFilterBox.Text != null && ncd.colFilterBox.Text != "")
				col.Filter = ncd.colFilterBox.Text;
			if(ncd.colDefaultBox.Text != null && ncd.colDefaultBox.Text != "")
			{
				col.DefaultValue = (object) ncd.colDefaultBox.Text;
			}
			if(ncd.colAllowNullBox.Checked)
				col.AllowNull = true;
			else
				col.AllowNull = false;
			if(ncd.colReadOnlyBox.Checked)
				col.ReadOnly = true;
			if(ncd.colUniqueBox.Checked)
				col.Unique = true;
			if(ncd.colAutoBox.Checked)
			{
				col.AutoIncrement = true;
				if(ncd.colAutoStartBox.Text != null && ncd.colAutoStartBox.Text != "")
					col.AutoIncrementStart = long.Parse(ncd.colAutoStartBox.Text);
				if(ncd.colAutoStepBox.Text != null && ncd.colAutoStepBox.Text != "")
					col.AutoIncrementStep = long.Parse(ncd.colAutoStepBox.Text);
			}
			// Adding the column
			col.Add();
			int index = this.colList.Items.Add(col.Name);
			this.colList.SelectedIndex = index;
			RefreshColumnEditor();
		}
		
		/// <summary>
		/// Column name validation.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColNameBoxValidating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			Class cls = (Class) tree.Classes.GetByIndex(this.classList.SelectedIndex);
			// Checking the syntax
			Regex re = new Regex(@"^[\w_\ \-]+$");
			if(re.IsMatch(this.colNameBox.Text))
			{
				bool exists = false;
				for(int i = 0; i < cls.Columns.Count; i++)
				{
					if(((Column) cls.Columns.GetByIndex(i)).Name == this.colNameBox.Text)
					{
						exists = true;
						break;
					}
				}
				if(exists)
				{
					if(culture == "ru")
						MessageBox.Show("Имя поля должно быть уникальным.", "Неверный ввод");
					else
						MessageBox.Show("Column name must be unique.", "Wrong input");
					e.Cancel = true;
				}
				else
					e.Cancel = false;
			}
			else
			{
				if(culture == "ru")
					MessageBox.Show("Имя может содержать буквы, цифры, пробел, знаки подчеркивания и дефис.", "Неверный ввод");
				else
					MessageBox.Show("The name can contain alphanumeric characters, spaces, underscores and dashes.", "Wrong input");
				e.Cancel = true;
			}
		}
		
		/// <summary>
		/// Column caption validation.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColCaptionBoxValidating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			// Really needed?
			// See NewColumnDialog.ColCaptionBoxValidating()
			e.Cancel = false;
		}
		
		/// <summary>
		/// Column length validation.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColLengthBoxValidating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			// Checking the syntax
			Regex re = new Regex(@"^\d{0,10}$");
			if(re.IsMatch(this.colLengthBox.Text))
			{
				long val = long.Parse(this.colLengthBox.Text);
				if(val > int.MaxValue)
				{
					if(culture == "ru")
						MessageBox.Show("Введено слишком большое число.", "Неверный ввод");
					else
						MessageBox.Show("The number is too big.", "Wrong input");
					e.Cancel = true;
				}
				else
					e.Cancel = false;
			}
			else
			{
				if(culture == "ru")
					MessageBox.Show("Введите число не длиннее 10 цифр.", "Неверный ввод");
				else
					MessageBox.Show("Enter a number not longer than 10 digits.", "Wrong input");
				e.Cancel = true;
			}
		}
		
		/// <summary>
		/// Validates the default value.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColDefaultBoxValidating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			// Null is nothing
			if(this.colDefaultBox.Text == null || this.colDefaultBox.Text == "")
			{
				e.Cancel = false;
				return;
			}
			// Checking syntax
			if(this.colTypeCombo.SelectedIndex > 0 && this.colTypeCombo.SelectedIndex < 4)
			{
				// Digital format
				Regex re = new Regex(@"^\-?\d+$");
				if(re.IsMatch(this.colDefaultBox.Text))
				{
					e.Cancel = false;
				}
				else
				{
					if(culture == "ru")
						MessageBox.Show("Введите целое число согласно выбранному типу.", "Неверный ввод");
					else
						MessageBox.Show("Enter an integer according to the data type you have chosen.", "Wrong input");
					e.Cancel = true;
				}
			}
			else if(this.colTypeCombo.SelectedIndex == 4)
			{
				// Float format
				Regex re = new Regex(@"^\-?\d+\.\d+$");
				if(re.IsMatch(this.colDefaultBox.Text))
				{
					e.Cancel = false;
				}
				else
				{
					if(culture == "ru")
						MessageBox.Show("Введите десятичную дробь с плавающей точкой.", "Неверный ввод");
					else
						MessageBox.Show("Enter a valid float number.", "Wrong input");
					e.Cancel = true;
				}
			}
			else
			{
				e.Cancel = false;
			}
		}
		
		/// <summary>
		/// Turns auto-increment on.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColAutoBoxCheckedChanged(object sender, System.EventArgs e)
		{
			if(this.colAutoBox.Checked)
			{
				this.colDefaultBox.Enabled = false;
				this.colAllowNullBox.Checked = true;
				this.colAllowNullBox.Enabled = false;
				this.colAutoStartBox.Enabled = true;
				this.colAutoStepBox.Enabled = true;
				this.colReadOnlyBox.Enabled = true;
				this.colReadOnlyBox.Checked = true;
				this.colUniqueBox.Checked = true;
			}
			else
			{
				this.colDefaultBox.Enabled = true;
				this.colAllowNullBox.Enabled = true;
				this.colAutoStartBox.Enabled = false;
				this.colAutoStepBox.Enabled = false;
				this.colReadOnlyBox.Checked = false;
				this.colReadOnlyBox.Enabled = false;
				this.colUniqueBox.Checked = false;
			}
		}
		
		/// <summary>
		/// Auto increment seed validation.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColAutoStartBoxValidating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			// Checking the syntax
			Regex re = new Regex(@"^\d{0,10}$");
			if(re.IsMatch(this.colAutoStartBox.Text))
			{
				e.Cancel = false;
			}
			else
			{
				if(culture == "ru")
					MessageBox.Show("Введите число не длиннее 10 цифр.", "Неверный ввод");
				else
					MessageBox.Show("Enter a number not longer than 10 digits.", "Wrong input");
				e.Cancel = true;
			}
		}
		
		/// <summary>
		/// Auto increment step validation.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColAutoStepBoxValidating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			// Checking the syntax
			Regex re = new Regex(@"^\d{0,10}$");
			if(re.IsMatch(this.colAutoStepBox.Text))
			{
				e.Cancel = false;
			}
			else
			{
				if(culture == "ru")
					MessageBox.Show("Введите число не длиннее 10 цифр.", "Неверный ввод");
				else
					MessageBox.Show("Enter a number not longer than 10 digits.", "Wrong input");
				e.Cancel = true;
			}
		}
		
		/// <summary>
		/// Data type selection.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColTypeComboSelectedIndexChanged(object sender, System.EventArgs e)
		{
			// MaxLength is valid for string only
			if(this.colTypeCombo.SelectedIndex == 0)
				this.colLengthBox.Enabled = true;
			else
				this.colLengthBox.Enabled = false;
			// AutoIncrement is valid for integers only
			if(this.colTypeCombo.SelectedIndex > 0 && this.colTypeCombo.SelectedIndex < 4)
			{
				this.colAutoBox.Enabled = true;
			}
			else
			{
				this.colAutoBox.Checked = false;
				this.colAutoBox.Enabled = false;
			}
		}
		
		/// <summary>
		/// Undoes lates edit operations.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColEditCancelClick(object sender, System.EventArgs e)
		{
			// Just refresh the editor
			RefreshColumnEditor();
		}
		
		/// <summary>
		/// Applies the changes made to the column.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColEditApplyClick(object sender, System.EventArgs e)
		{
			// Check if the type is chosen
			if(this.colTypeCombo.SelectedIndex < 0)
			{
				if(culture == "ru")
					MessageBox.Show("Вы должны выбрать тип данных.", "Тип данных");
				else
					MessageBox.Show("You must select data type.", "Data type");
			}
			else if(!this.colAllowNullBox.Checked && (this.colDefaultBox.Text == null || this.colDefaultBox.Text == ""))
			{
				if(culture == "ru")
					MessageBox.Show("Если поле не принимает null, то должно быть задано значение по умолчанию.", "Значение по умолчанию");
				else
					MessageBox.Show("You must set the default value if the column does not allow null.", "Default value");
			}
			else
			{
				// Proceed with editing
				Column col = (Column) ((Class) tree.Classes.GetByIndex(this.classList.SelectedIndex)).Columns.GetByIndex(this.colList.SelectedIndex);
				col.Name = this.colNameBox.Text;
				switch(this.colTypeCombo.SelectedIndex)
				{
					case 0:
						col.DataType = typeof(string);
						break;
					case 1:
						col.DataType = typeof(byte);
						break;
					case 2:
						col.DataType = typeof(int);
						break;
					case 3:
						col.DataType = typeof(long);
						break;
					case 4:
						col.DataType = typeof(double);
						break;
					case 5:
						col.DataType = typeof(bool);
						break;
				}
				if(this.colCaptionBox.Text != null)
					col.Caption = this.colCaptionBox.Text;
				if(this.colLengthBox.Text != null && this.colLengthBox.Text != "")
					col.MaxLength = int.Parse(this.colLengthBox.Text);
				if(this.colFilterBox.Text != null && this.colFilterBox.Text != "")
					col.Filter = this.colFilterBox.Text;
				if(this.colDefaultBox.Text != null && this.colDefaultBox.Text != "")
				{
					col.DefaultValue = (object) this.colDefaultBox.Text;
				}
				if(this.colAllowNullBox.Checked)
					col.AllowNull = true;
				if(this.colReadOnlyBox.Checked)
					col.ReadOnly = true;
				if(this.colUniqueBox.Checked)
					col.Unique = true;
				if(this.colAutoBox.Checked)
				{
					col.AutoIncrement = true;
					if(this.colAutoStartBox.Text != null && this.colAutoStartBox.Text != "")
						col.AutoIncrementStart = long.Parse(this.colAutoStartBox.Text);
					if(this.colAutoStepBox.Text != null && this.colAutoStepBox.Text != "")
						col.AutoIncrementStep = long.Parse(this.colAutoStepBox.Text);
				}
				// Applying changes
				col.Update();
				//this.colList.Items[this.colList.SelectedIndex] = col.Name;
				RefreshClassEditor();
				// Find new index
				this.colList.SelectedIndex = this.colList.Items.IndexOf(col.Name);
			}
		}
		
		/// <summary>
		/// Removes the column from the class.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColDelBtnClick(object sender, System.EventArgs e)
		{
			RemoveColumnDialog rcd = new RemoveColumnDialog();
			rcd.ShowDialog();
			if(rcd.DialogResult == DialogResult.OK)
			{
				// Removing the column
				Column col = (Column) ((Class) tree.Classes.GetByIndex(this.classList.SelectedIndex)).Columns.GetByIndex(this.colList.SelectedIndex);
				col.Remove();
				this.colList.Items.RemoveAt(this.colList.SelectedIndex);
			}
		}
		
		/// <summary>
		/// Duplicates the column.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ColCopyBtnClick(object sender, System.EventArgs e)
		{
			// Getting the class
			Class cls = (Class) tree.Classes.GetByIndex(this.classList.SelectedIndex);
			// Column names must be unique!
			string colName = (culture == "ru") ? "Поле" : "Column";
			// Appending a tail if needed
			bool exists;
			uint num = 0;
			string temp;
			do
			{
				exists = false;
				if(num == 0)
					temp = colName;
				else
					temp = colName + num.ToString();
				for(int i = 0; i < cls.Columns.Count; i++)
				{
					if(((Column) cls.Columns.GetByIndex(i)).Name == temp)
					{
						exists = true;
						break;
					}
				}
				num++;
			}
			while(exists);
			colName = temp;
			// Creating the column
			Column col = new Column(colName, cls);
			// Inheriting a selected one
			col.Inherit((Column) cls.Columns.GetByIndex(this.colList.SelectedIndex));
			// Adding the column
			col.Add();
			int index = this.colList.Items.Add(col.Name);
			this.colList.SelectedIndex = index;
			RefreshColumnEditor();
		}
		
		/// <summary>
		/// Sets this class as default dropdown position
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ClassSetDefaultCheckedChanged(object sender, System.EventArgs e)
		{
			if(!defaultClicked)
				return;
			if(this.classSetDefault.Checked)
			{
				defaultClass = classList.Items[this.classList.SelectedIndex].ToString();
				RefreshClassDropDown(this.searchClassCombo);
				RefreshClassDropDown(this.selNodeClass);
				RefreshClassDropDown(this.childClass);
			}
			else
			{
				defaultClass = null;
				RefreshClassDropDown(this.searchClassCombo);
				RefreshClassDropDown(this.selNodeClass);
				RefreshClassDropDown(this.childClass);
			}
		}
		
		/// <summary>
		/// Changes the selected node's class.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void SelNodeClassChangeClick(object sender, System.EventArgs e)
		{
			// Getting the node
			Node node = new Node(tree, uint.Parse(treeView.SelectedNode.Tag.ToString()));
			// Getting a selected class
			if(this.selNodeClass.SelectedIndex == -1)
			{
				// Empty class (cid == 0)
				node.ParentClass = null;
			}
			else
			{
				// A distinct class
				Class cls = (Class) tree.Classes[this.selNodeClass.Items[this.selNodeClass.SelectedIndex]];
				// Performing the assignment
				node.ParentClass = cls;
			}
			node.Update();
			// Refresh view
			RefreshNodeView(node);
		}
		
		/// <summary>
		/// Occurs when the class filter is changed.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ChildClassSelectedIndexChanged(object sender, System.EventArgs e)
		{
			// Getting the node
			Node node = new Node(tree, uint.Parse(treeView.SelectedNode.Tag.ToString()));
			// Just refresh the view
			RefreshChildrenView(node);
		}
		
		/// <summary>
		/// Validates search string input according to the data type of the selected field.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void SearchTextBoxValidating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			// No validating for empty class/column
			if(this.searchClassCombo.SelectedIndex < 0 || this.searchColumnCombo.SelectedIndex < 0)
			{
				e.Cancel = false;
				return;
			}
			// Getting the class and the column
			Class cls = (Class) tree.Classes[this.searchClassCombo.Items[this.searchClassCombo.SelectedIndex]];
			Column col = (Column) cls.Columns[this.searchColumnCombo.Items[this.searchColumnCombo.SelectedIndex]];
			// Checking a search string. Type-specific behaviour.
			if(col.DataType == typeof(byte) || col.DataType == typeof(int) || col.DataType == typeof(long))
			{
				// Digital format
				Regex re = new Regex(@"^\-?\d+$");
				if(re.IsMatch(this.searchTextBox.Text))
				{
					e.Cancel = false;
				}
				else
				{
					if(culture == "ru")
						MessageBox.Show("Введите целое число согласно выбранному типу.", "Неверный ввод");
					else
						MessageBox.Show("Enter an integer according to the data type you have chosen.", "Wrong input");
					e.Cancel = true;
				}
			}
			else if(col.DataType == typeof(double))
			{
				// Float format
				Regex re = new Regex(@"^\-?\d+\.\d+$");
				if(re.IsMatch(this.searchTextBox.Text))
				{
					e.Cancel = false;
				}
				else
				{
					if(culture == "ru")
						MessageBox.Show("Введите десятичную дробь с плавающей точкой.", "Неверный ввод");
					else
						MessageBox.Show("Enter a valid float number.", "Wrong input");
					e.Cancel = true;
				}
			}
			else
			{
				// Nothing else to check otherwise
				e.Cancel = false;
			}
		}
		
		/// <summary>
		/// Searches for the nodes and displays them in selection grids.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void SearchFindClick(object sender, System.EventArgs e)
		{
			// Check for required selections
			if(this.searchClassCombo.SelectedIndex < 0 || this.searchColumnCombo.SelectedIndex < 0)
			{
				if(culture == "ru")
					MessageBox.Show("Для поиска необходимо выбрать класс и поле сравнения.", "Поиск остановлен");
				else
					MessageBox.Show("Node class and a column for comparison should be selected in order to continue searching.", "The search has been canceled");
				return;
			}
			// Get the class and the column
			Class cls = (Class) tree.Classes[this.searchClassCombo.Items[this.searchClassCombo.SelectedIndex]];
			Column col = (Column) cls.Columns[this.searchColumnCombo.Items[this.searchColumnCombo.SelectedIndex]];
			// Get the view from the tree and bind it to the grid
			dataSelGrid.DataSource = tree.Search(cls, col, this.searchTextBox.Text, false);
			dataSelGrid.CaptionText = (culture == "ru") ? "Результаты поиска" : "Search results";
			// Move to the data tab
			this.tabControl.SelectedIndex = 1;
		}
		
		/// <summary>
		/// Sets an auxilliary clicked flag for default class box.
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void ClassSetDefaultMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			defaultClicked = true;
		}
		
		/// <summary>
		/// Loads the column list when class for searching has been chosen
		/// </summary>
		/// <param name="sender">Sender object.</param>
		/// <param name="e">Event arguments.</param>
		void SearchClassComboSelectedIndexChanged(object sender, System.EventArgs e)
		{
			// Clear the list
			this.searchColumnCombo.Items.Clear();
			// Regenerate if needed
			if(this.searchClassCombo.SelectedIndex >= 0)
			{
				// Determine the class to search for
				Class cls = (Class) tree.Classes[this.searchClassCombo.Items[this.searchClassCombo.SelectedIndex]];
				// Fill up the list
				for(int i = 0; i < cls.Columns.Count; i++)
				{
					Column col = (Column) cls.Columns.GetByIndex(i);
					this.searchColumnCombo.Items.Add(col.Name);
				}
			}
		}
		
		/// <summary>
		/// Tree modified state change event handler.
		/// </summary>
		/// <param name="state">State value</param>
		void TreeModifiedStateChanged(bool state)
		{
			if(state)
			{
				// The tree has been modified
				if(modifiedDisplay)
				{
					// Already displayed, bypass
				}
				else
				{
					// Display modification
					this.Text = tree.Name + "*";
					modifiedDisplay = true;
				}
			}
			else
			{
				// Tree hasn't been modified
				if(modifiedDisplay)
				{
					// Change display to unmodified
					this.Text = tree.Name;
					modifiedDisplay = false;
				}
				else
				{
					// Already undisplayed, bypass
				}
			}
		}
	}
}
